package nio.engine;


import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.HashMap;
import java.util.Iterator;

import nio.engine.AcceptCallback;
import nio.engine.ConnectCallback;
import nio.engine.NioEngine;
import nio.engine.NioServer;
public class NioEngineImplementation extends NioEngine{
	private Selector selector;
	// A completer ( nioServerAndServerSocketChannel socketChannelAndNioChannel socketChannelAndConnectCallback )
	public NioEngineImplementation() throws Exception {
		//Service-provider class for selectors and selectable channels.  
		selector = SelectorProvider.provider().openSelector();
			
		//nioServerAndServerSocketChannel = new HashMap<ServerSocketChannel, NioServer>();
		//socketChannelAndNioChannel = new HashMap<SocketChannel, NioChannelImplementation>();
		//socketChannelAndConnectCallback  = new HashMap<SocketChannel, ConnectCallback>();
	}
	
	@Override
	public void mainloop() {
		while (true) {
			try {
				// select
				selector.select();
				// 
				Iterator<?> selectedKeys = this.selector.selectedKeys().iterator();

				while (selectedKeys.hasNext()) {

					SelectionKey key = (SelectionKey) selectedKeys.next();
					selectedKeys.remove();
					//check key 
					if (!key.isValid()) {
						System.out.println("The key is not valid");
						continue;
					} else if (key.isAcceptable()) {
						handleAccept(key);
					} else if (key.isReadable()) {
						handleRead(key);
					} else if (key.isWritable()) {
						handleWrite(key);
					} else if (key.isConnectable()) {
						handleConnection(key);
					} else {
						System.out.println("Unknown key");
					}
				}
			} catch (Exception e) {
				panic("Error during the selection of a key");
			}
		}
	}
		
	public Selector getSelector(){
		return this.selector;
	}
    // A completer 

	public void handleAccept(SelectionKey key) throws IOException{
	}
	
    // A completer 
	
	public void handleRead(SelectionKey key) throws IOException{	
		}
	
	// A completer
	public void handleWrite(SelectionKey key) throws IOException{
	}
	
	// A completer
	public void askWriting(NioChannelClass channel)throws IOException{
	}
	
	// A completer
	public void handleConnection(SelectionKey key)throws IOException{
	}
	
	// A FINIR , problème serveur 
	@Override
	public NioServer listen(int port, AcceptCallback acceptCallback) throws IOException{

		NioServer server = null;

		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.configureBlocking(false);

		InetSocketAddress addressToBind = new InetSocketAddress("localhost", port);
		serverSocketChannel.socket().bind(addressToBind);
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		//server = new NioServerClass(serverSocketChannel, acceptCallback);

		// We store the server somewhere with the ServerSocketChannel associated
		//nioServerAndServerSocketChannel.put(serverSocketChannel, server);

		return server;

	}

	@Override
	public void connect(InetAddress inetAddress, int port, ConnectCallback connectCallback)
			throws UnknownHostException, SecurityException, IOException{
		
		SocketChannel socketChannel = SocketChannel.open();
		socketChannel.configureBlocking(false);

		socketChannel.register(selector, SelectionKey.OP_CONNECT);
		socketChannel.connect(new InetSocketAddress(inetAddress, port));
		
		//socketChannelAndConnectCallback.put(socketChannel, connectCallback);

	}
		
}

